package Control;

import Entidades.grafo.Grafo;
import Entidades.promethee.*;
import GUI.Principal;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;


/**
 *
 * @author Cristian Lopez
 */
public class GestorProcesamiento
{
    private double valores[][], pesos[];
    private int tipo[], funcionPreferencia[];
    private double p[], q[], sigma[];
    private String criterios[], alternativas[];
    private Promethee promethee;
    public final int PROMETHEE_I = 1;
    public final int PROMETHEE_II = 2;
    // PRIMER PASO
    private double matrizDiferencias[][];
    private double matrizFuncionPreferencia[][];
    // SEGUNDO PASO
    private double indicesPreferencia[][];
    // TERCER PASO
    private double flujoSuperacionPositivo[];
    private double flujoSuperacionNegativo[];
    // CUARTO PASO
    private double preorden[];
    private Grafo grafo;
    private String pathGrafo;
    private static int version = 0;

    public GestorProcesamiento(String criterios[], String alternativas[], double valores[][], double pesos[], int tipo[], int funcionPreferencia[], double p[], double q[], double sigma[], int tipoPromethee)
    {
        this.criterios = criterios;
        this.alternativas = alternativas;
        this.valores = valores;
        this.pesos = pesos;
        this.tipo = tipo;
        this.funcionPreferencia = funcionPreferencia;
        this.p = p;
        this.q = q;
        this.sigma = sigma;

        if (tipoPromethee == PROMETHEE_I)
        {
            promethee = new PrometheeI(valores, pesos, tipo, funcionPreferencia, p, q, sigma);
        }
        else if (tipoPromethee == PROMETHEE_II)
        {
            promethee = new PrometheeII(valores, pesos, tipo, funcionPreferencia, p, q, sigma);
        }

        version++;
    }

    public void resolver()
    {
        // PRIMER PASO
        matrizDiferencias = promethee.calcularDiferencias();
        matrizFuncionPreferencia = promethee.calcularFuncionPreferencia(matrizDiferencias);

        // SEGUNDO PASO
        indicesPreferencia = promethee.calcularIndicesPreferencias(matrizFuncionPreferencia);

        // TERCER PASO
        flujoSuperacionPositivo = promethee.calcularFlujoSuperacionPositivo(indicesPreferencia);
        flujoSuperacionNegativo = promethee.calcularFlujoSuperacionNegativo(indicesPreferencia);

        // CUARTO PASO
        preorden = promethee.obtenerPreorden(flujoSuperacionPositivo, flujoSuperacionNegativo);
    }

    public void armarGrafo()
    {
        
        grafo = new Grafo(preorden.length / 2);
        int posX = 50, posY = 50;
        boolean flag = true;
        for (int i = 0; i < preorden.length - 1; i += 2)
        {
            grafo.agregarNodo("A" + ((int) preorden[i] + 1), posX, posY, 40, 40);


            posX += 120;
            if (flag)
            {
                flag = false;
                posY -= 40;
            }
            else
            {
                flag = true;
                posY += 80;
            }
        }

        for (int i = 1; i < preorden.length; i += 2)
        {
            if (i + 2 > preorden.length)
            {
                continue;
            }
            if (preorden[i] > preorden[i + 2])
            {
                grafo.unir(i / 2, (i + 2) / 2);
            }
            else
            {
                if (i > 1)
                {
                    grafo.unir((i - 2) / 2, (i + 2) / 2);
                }
                int pos = i + 2;
                while (pos < preorden.length)
                {
                    if (pos + 2 < preorden.length && preorden[pos] == preorden[pos + 2])
                    {
                        pos += 2;
                    }
                    else
                    {
                        break;
                    }
                }
                if (i == 1 && pos >= preorden.length)
                {
                    continue;
                }
                for (int j = i; j <= pos; j += 2)
                {
                    if (pos + 2 > preorden.length)
                    {
                        break;
                    }
                    grafo.unir(j / 2, (pos + 2) / 2);
                }
                i = pos + 2;
            }
        }

        
        BufferedImage bi = new BufferedImage(800, 350, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = (Graphics2D) bi.getGraphics();

        g.setColor(Color.WHITE);
        g.fillRect(0, 0, bi.getWidth(), bi.getHeight());

        

        grafo.dibujarGrafo(g);
        ////////
            File dir = new File("." + File.separator + "res" + File.separator + "tmp");
            if (!dir.exists())
            {
                dir.mkdir();
            }
            if (PrometheeI.class.isInstance(promethee))
            {
                pathGrafo = "." + File.separator + "res" + File.separator + "/tmp/grafPI" + version + ".png";
            }
            else
            {
                pathGrafo = "." + File.separator + "res" + File.separator + "/tmp/grafPII" + version + ".png";
            }

            

            File arch = new File(pathGrafo);
            if (arch.exists())
            {
                arch.delete();
            }

            try{
            ImageIO.write(bi, "png", arch);//No funciona en .JAR

        }
        catch (IOException e)
        {
            System.out.println("Error de escritura");
        }

        catch(Exception e){JOptionPane.showMessageDialog(null,e.toString(), "Error del orto al escribir", JOptionPane.ERROR_MESSAGE);
            return;
                }

    }

    public String[][] getMatrizInicial()
    {
        String matriz[][] = new String[valores.length + 6][valores[0].length];
        for (int i = 0; i < matriz.length; i++)
        {
            for (int j = 0; j < matriz[i].length; j++)
            {
                if (i < 6)
                {
                    if (i == 0)
                    {
                        matriz[i][j] = String.valueOf(pesos[j]);
                    }
                    else if (i == 1)
                    {
                        matriz[i][j] = (tipo[j] == Promethee.TIPO_MAXIMIZANTE) ? "MAX" : "MIN";
                    }
                    else if (i == 2)
                    {
                        matriz[i][j] = Principal.valoresFPR[(funcionPreferencia[j] - 1)];
                    }
                    else if (i == 3)
                    {
                        matriz[i][j] = String.valueOf(p[j]);
                    }
                    else if (i == 4)
                    {
                        matriz[i][j] = String.valueOf(q[j]);
                    }
                    else if (i == 5)
                    {
                        matriz[i][j] = String.valueOf(sigma[j]);
                    }
                }
                else
                {
                    matriz[i][j] = String.valueOf(valores[i - 6][j]);
                }
            }
        }
        return matriz;
    }

    public double[][] getMatrizDiferencias()
    {
        return matrizDiferencias;
    }

    public double[][] getMatrizFuncionPreferencia()
    {
        return matrizFuncionPreferencia;
    }

    public double[][] getMatrizIndicePreferencia()
    {
        return indicesPreferencia;
    }

    public double[] getFlujoSuperacionPositivo()
    {
        return flujoSuperacionPositivo;
    }

    public double[] getFlujoSuperacionNegativo()
    {
        return flujoSuperacionNegativo;
    }

    public double[] getPreorden()
    {
        return preorden;
    }

    public String getPathGrafo()
    {
        return pathGrafo;
    }

    public double[][] calcularTranspuesta(double matriz[][])
    {
        double mTranspuesta[][] = new double[matriz[0].length][matriz.length];
        for (int j = 0; j < matriz[0].length; j++)
        {
            for (int i = 0; i < matriz.length; i++)
            {
                mTranspuesta[j][i] = matriz[i][j];
            }
        }
        return mTranspuesta;
    }

    public static double getDecimal(int numeroDecimales, double decimal)
    {
        decimal = decimal * (java.lang.Math.pow(10, numeroDecimales));
        decimal = java.lang.Math.round(decimal);
        decimal = decimal / java.lang.Math.pow(10, numeroDecimales);

        return decimal;
    }
}
